Transcriptome of 5-week-old Col-0 and isi1-2 distal leaves 13 in untreated controls or upon wounding leave 8

Data from https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE157938 In that study, IMPAIRED SUCROSE INDUCTION 1 (ISI1) was identified as a player in long distance wound signaling in Arabidopsis. To further assess the impact of ISI1 on the wound response, authors tested the transcriptomes of the wounded isi1-2 mutants in comparison with wounded wild type plants, in order to find genes that were deregulated in isi1 loss-of-function mutants.

Two groups of plants: control (Col-0) and isi-mutant plants (isi1-2) with three biological replicates per group; Distal leaves 13 were collected one hour after wounding leave 8 (in wounded plants) or without any treatment (unwounded plants). Two individual plants were pooled for one replicate; single read design.

Set your working directory with Kallisto results

Checking for required packages and install, if necessary

library(tidyverse)
library(tximport)
library(DESeq2)
library(pheatmap)
library(RColorBrewer)
library(rhdf5)
library(WGCNA)
library(clusterProfiler)
library(org.At.tair.db)
library(ggridges)

Importing Transcript-Level Quantification Data and creating DESeq2 Dataset

samples <- read_tsv("phenotable.tsv", show_col_types = FALSE)
head(samples, 12)
files <- file.path(samples$path, "abundance.h5")  # path to abundance files in kallisto dirs
files
 [1] "SRR12649393_1/abundance.h5" "SRR12649394_1/abundance.h5" "SRR12649395_1/abundance.h5" "SRR12649396_1/abundance.h5"
 [5] "SRR12649397_1/abundance.h5" "SRR12649398_1/abundance.h5" "SRR12649399_1/abundance.h5" "SRR12649400_1/abundance.h5"
 [9] "SRR12649401_1/abundance.h5" "SRR12649402_1/abundance.h5" "SRR12649403_1/abundance.h5" "SRR12649404_1/abundance.h5"

The data is from Kallisto, a tool for quantifying RNA-seq data at the transcript level. • tximport: Imports transcript-level quantification data from Kallisto. • DESeqDataSetFromTximport: Converts the imported data into a DESeq2 dataset, setting up for differential expression analysis. • ddsTxi: Contains the DESeq2 dataset object which includes the count data, sample metadata, and design formula.

txi <- tximport(files, type = 'kallisto', txOut = T)
1 2 3 4 5 6 7 8 9 10 11 12 
ddsTxi <- DESeqDataSetFromTximport(txi,
                                   colData = samples,
                                   design = ~ genotype*condition) 
Warning in DESeqDataSet(se, design = design, ignoreRank) :
  some variables in design formula are characters, converting to factors
using counts and average transcript lengths from tximport
ddsTxi
class: DESeqDataSet 
dim: 48359 12 
metadata(1): version
assays(2): counts avgTxLength
rownames(48359): AT1G76820.1 ATMG00060.1 ... AT1G71740.1 AT3G05780.1
rowData names(0):
colnames: NULL
colData names(4): sample genotype condition path

Filter Low-Expression Genes and relevel the genotype Factor The code keeps only those genes where the sum of counts across all samples is at least 10 ‘relevel’ changes the reference level of the genotype factor to ensures that all comparisons of genotype effects are made relative to the “WT” genotype.

dds <- ddsTxi[rowSums(counts(ddsTxi)) >= 10,]
dds$genotype <- relevel(dds$genotype, ref = "WT")

Run Differential Expression Analysis

dds <- DESeq(dds, fitType = 'local')
estimating size factors
using 'avgTxLength' from assays(dds), correcting for library size
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
dds
class: DESeqDataSet 
dim: 37465 12 
metadata(1): version
assays(6): counts avgTxLength ... H cooks
rownames(37465): AT1G76820.1 ATMG00060.1 ... AT2G27490.2 AT1G71740.1
rowData names(30): baseMean baseVar ... deviance maxCooks
colnames: NULL
colData names(4): sample genotype condition path

Variance-stabilizing transformation of data The VST aims to stabilize the variance across the range of mean expression values, making the data more suitable for downstream analyses such as clustering or principal component analysis (PCA). blind = FALSE: This argument controls whether the transformation should be performed without accounting for the experimental design. Setting blind = FALSE means that the transformation will use the information from the experimental design (i.e., it will not “blind” to the design), which is often preferred when you are interested in preserving the relationship between conditions in the transformed data. fitType = ‘local’: Specifies the method for estimating the dispersion used in the transformation. The ‘local’ option fits a local smoothing spline to the dispersion estimates, which can provide a better fit for datasets with varying dispersion values. (it can run without any fit type and set it automatically)

# variance-stabilizing transformation of data (important for clustering or ML)
vsd <- vst(dds, blind = FALSE, fitType = 'local')
vsd
class: DESeqTransform 
dim: 37465 12 
metadata(1): version
assays(1): ''
rownames(37465): AT1G76820.1 ATMG00060.1 ... AT2G27490.2 AT1G71740.1
rowData names(30): baseMean baseVar ... maxCooks dispFit
colnames(12): 1 2 ... 11 12
colData names(4): sample genotype condition path

Let’s look at the results:

res <- results(dds)
res 
log2 fold change (MLE): genotypeISI.conditionW 
Wald test p-value: genotypeISI.conditionW 
DataFrame with 37465 rows and 6 columns
             baseMean log2FoldChange     lfcSE       stat    pvalue      padj
            <numeric>      <numeric> <numeric>  <numeric> <numeric> <numeric>
AT1G76820.1  175.4066      0.0917138 0.2500738   0.366747  0.713808  0.987831
ATMG00060.1   12.0979      0.2923877 1.0995924   0.265906  0.790312  0.995532
AT4G16360.1  762.0852     -0.0319303 0.0806895  -0.395718  0.692313  0.985234
AT5G26800.1  299.0979     -0.2561651 0.1766372  -1.450234  0.146993  0.699143
AT4G16110.1  209.2414      0.0712498 0.2337945   0.304754  0.760554  0.993554
...               ...            ...       ...        ...       ...       ...
AT1G24405.1   8.52672     -0.6597421  0.931364 -0.7083612  0.478721  0.936659
AT2G27490.4 102.54183      0.2235853  0.368364  0.6069676  0.543872  0.956735
AT2G27490.1  17.19200      0.3401511  1.082508  0.3142250  0.753350  0.992456
AT2G27490.2  66.26305      0.0305085  0.514765  0.0592669  0.952740  0.999397
AT1G71740.1   2.19925      1.3243985  1.680299  0.7881923  0.430584        NA
•   Base Mean provides the average expression level.
•   Log2 Fold Change indicates how the expression changes between conditions.
•   LfcSE gives the variability in the log2 fold change estimate.
•   Stat is the Wald statistic used in hypothesis testing.

And how many of these results are significant?

res005 <- results(dds, alpha=0.05)
summary(res005)

out of 37465 with nonzero total read count
adjusted p-value < 0.05
LFC > 0 (up)       : 235, 0.63%
LFC < 0 (down)     : 257, 0.69%
outliers [1]       : 367, 0.98%
low counts [2]     : 2180, 5.8%
(mean count < 2)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results

This means that out of 37,465 genes tested, 3,458 were identified as significant with a padj less than 0.05. The remaining genes did not pass this threshold and are considered insignificant.

Let’s look on names of our variables:

resultsNames(dds)
[1] "Intercept"              "genotype_ISI_vs_WT"     "condition_W_vs_UW"      "genotypeISI.conditionW"

Intercept = genotypeWT.conditionUW. In this model, the intercept represents the baseline gene expression for the reference levels of both genotype and condition. Let’s arranged it by log2FoldChange:

order_indices <- order(-res$log2FoldChange)
res_sorted <- res[order_indices, ]
res_sorted
log2 fold change (MLE): genotypeISI.conditionW 
Wald test p-value: genotypeISI.conditionW 
DataFrame with 37465 rows and 6 columns
             baseMean log2FoldChange     lfcSE      stat      pvalue        padj
            <numeric>      <numeric> <numeric> <numeric>   <numeric>   <numeric>
AT1G10430.1  25.68831             30   6.00876   4.99271          NA          NA
AT5G03540.3  14.06154             30   6.01269   4.98944          NA          NA
AT4G33520.3   5.77803             30   6.03077   4.97449          NA          NA
AT1G35220.5   8.60384             30   6.01359   4.98870          NA          NA
AT4G34490.2  22.75369             30   6.00918   4.99236          NA          NA
...               ...            ...       ...       ...         ...         ...
AT3G49420.3   8.29872            -30   6.01296  -4.98922          NA          NA
AT3G07740.4   5.05402            -30   6.01742  -4.98552 6.17942e-07 0.000338702
AT1G76350.3   5.31241            -30   6.01653  -4.98626 6.15596e-07 0.000338702
AT4G21150.2  10.23504            -30   6.01242  -4.98967          NA          NA
AT1G80000.2  28.25891            -30   6.00807  -4.99329 5.93603e-07 0.000338702

Visualisation for the first gene

# Gene counts for a specific gene
plotCounts(dds, gene="AT1G10430.1", intgroup="genotype")

plotCounts(dds, gene="AT1G10430.1", intgroup="condition")

Volkano plot

res %>%
  as.data.frame %>% 
  filter(!is.na(log2FoldChange), !is.na(padj), log2FoldChange >= -2.5, log2FoldChange <= 2.5) %>%
  ggplot(aes(log2FoldChange, -log10(padj), color = padj < 0.05)) +
  geom_point() +
  scale_color_manual(values=c("black", "red")) +
  xlim(c(-2.5, 2.5))

** PCA plot **

plotPCA(vsd, intgroup=c("genotype", "condition"))
using ntop=500 top features by variance

Ideally, each group of replicates should cluster together in a PCA plot, reflecting similar gene expression profiles within each group. - Outlier in the ISI:UW Group: The fact that one replicate from the ISI:UW group clusters closer to the WT:UW group could suggest that the ISI1 loss-of-function mutation was not fully penetrant or did not manifest as strongly in that particular replicate. As a result, its gene expression profile is more similar to the wild-type unwounded (WT:UW) condition rather than to its intended group (ISI:UW).

  • This could occur if the mutation in ISI1 is variable in its effect or if there was some technical or biological reason why this replicate did not exhibit the expected mutant phenotype.

  • Clear Division Between W and UW Groups: The distinct separation of the wounded (W) and unwounded (UW) samples on the PCA plot indicates that the wounding has a strong and consistent effect on gene expression, regardless of genotype.

** MA plot **

Under a null hypothesis of no differential expression, most genes’ log2 fold changes should center tightly around 0. However, genes with higher absolute M values exhibit greater differential expression between conditions. An ideal MA plot will show the majority of genes along M=0 and outliers stretching towards the graph peripheries.

plotMA(dds)

Here the difference in expression of the entire model of differential expression is shown and we see that there are not many differentially expressed genes and some groups are noticeable in the graph. Let’s divide this graph by conditions and look at it separately. Wounded VS Unwouned

res <- results(dds, contrast=c("condition", "W", "UW"))
plotMA(res)

This plot looks more like an ideal MA graph with a large number of differentially expressed genes. What about ISI1-mutated VS WT?

res <- results(dds, contrast=c("genotype", "ISI", "WT"))
plotMA(res)

This plot appears to be close with the null hypothesis, and reveals small effect of the genotype. Plot a heatmap of 100 most expressed genes

# Plot a heatmap of 100 most expressed genes
select <- order(rowMeans(counts(dds,normalized=TRUE)),
                decreasing=TRUE)[1:100]
df <- as.data.frame(colData(dds)[,c("genotype", "condition")])
pheatmap(assay(vsd)[select,], 
         cluster_rows = TRUE, 
         show_rownames = TRUE, 
         cluster_cols = TRUE, 
         annotation_col = df,
         fontsize_row = 6)  # Adjust fontsize_row to your preference

We have a distinct separation of the wounded (W) and unwounded (UW) samples again, which indicates that the wounding has a strong and consistent effect on gene expression, regardless of genotype.

Plot of the distance between samples heatmap


sampleDistMatrix <- as.matrix(sampleDists)
rownames(sampleDistMatrix) <- paste(vsd$genotype, vsd$condition, sep="-")
colnames(sampleDistMatrix) <- paste(vsd$genotype, vsd$condition, sep="-")
colors <- colorRampPalette( rev(brewer.pal(9, "Blues")) )(255)
pheatmap(sampleDistMatrix,
         clustering_distance_rows=sampleDists,
         clustering_distance_cols=sampleDists,
         color = colors)

Same separation of the wounded (W) and unwounded (UW) samples again

Анализ обогащения

res
log2 fold change (MLE): genotype ISI vs WT 
Wald test p-value: genotype ISI vs WT 
DataFrame with 37465 rows and 6 columns
             baseMean log2FoldChange     lfcSE      stat     pvalue      padj
            <numeric>      <numeric> <numeric> <numeric>  <numeric> <numeric>
AT1G76820.1  175.4066     -0.2649083 0.1737217 -1.524900 0.12728393  0.757109
ATMG00060.1   12.0979      0.8078983 0.7976565  1.012840 0.31113669  0.930262
AT4G16360.1  762.0852      0.1453457 0.0553858  2.624239 0.00868427  0.253548
AT5G26800.1  299.0979     -0.0724616 0.1257496 -0.576237 0.56445501  0.999948
AT4G16110.1  209.2414     -0.0640335 0.1652295 -0.387543 0.69835422  0.999948
...               ...            ...       ...       ...        ...       ...
AT1G24405.1   8.52672       0.396784  0.678618  0.584695   0.558753  0.999948
AT2G27490.4 102.54183      -0.265294  0.263356 -1.007359   0.313762  0.931444
AT2G27490.1  17.19200      -0.436321  0.776040 -0.562240   0.573952  0.999948
AT2G27490.2  66.26305       0.313981  0.366080  0.857685   0.391067  0.970626
AT1G71740.1   2.19925      -1.849487  1.234794 -1.497810   0.134183        NA
summary(res)

out of 37465 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 346, 0.92%
LFC < 0 (down)     : 217, 0.58%
outliers [1]       : 367, 0.98%
low counts [2]     : 2906, 7.8%
(mean count < 3)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results
gene_ids <- rownames(res)
head(gene_ids, 99)
 [1] "AT1G76820.1" "ATMG00060.1" "AT4G16360.1" "AT5G26800.1" "AT4G16110.1" "AT4G15130.1" "ATMG01320.1" "AT3G57180.1" "AT2G06210.1"
[10] "AT1G60260.1" "AT1G64460.1" "AT5G18710.1" "AT5G60900.1" "AT4G15950.1" "AT3G08943.1" "AT3G52310.1" "AT4G16150.1" "AT3G55270.1"
[19] "AT1G60930.1" "AT4G35335.1" "AT5G11100.1" "AT1G18320.1" "AT5G16970.1" "AT2G43120.2" "AT2G43120.1" "AT3G18710.1" "AT4G25880.4"
[28] "AT4G25880.2" "AT4G25880.5" "AT4G25880.1" "AT4G25880.3" "AT1G78930.1" "AT3G07950.1" "AT4G03450.2" "AT4G03450.1" "AT1G71695.1"
[37] "AT1G58983.1" "AT1G12980.1" "AT5G41480.1" "AT3G51870.1" "AT4G29950.3" "AT4G29950.1" "AT4G29950.2" "AT3G18310.1" "AT5G07360.3"
[46] "AT5G07360.1" "AT5G07360.2" "AT4G08535.1" "AT4G08535.2" "AT4G26490.1" "AT5G46240.1" "AT5G62260.3" "AT5G62260.1" "AT4G16955.1"
[55] "AT3G25717.1" "AT5G41908.1" "AT2G21390.1" "AT3G48330.2" "AT3G48330.3" "AT3G48330.4" "AT3G48330.1" "AT4G32710.1" "AT3G46440.1"
[64] "AT3G46440.2" "AT1G56250.1" "AT3G16830.1" "AT5G04950.1" "AT4G13720.1" "AT4G13720.2" "AT5G50110.1" "AT5G50110.2" "AT3G03305.1"
[73] "AT2G38310.1" "AT2G26900.1" "AT1G69810.1" "AT1G72450.2" "AT1G72450.1" "AT5G03560.3" "AT5G03560.4" "AT5G03560.1" "AT5G03560.2"
[82] "AT4G27340.3" "AT4G27340.2" "AT4G27340.1" "AT1G76280.4" "AT1G76280.2" "AT1G76280.5" "AT1G76280.1" "AT3G03272.1" "AT3G28960.1"
[91] "AT3G28960.4" "AT3G28960.3" "AT3G28960.2" "AT3G28960.5" "AT3G10210.1" "AT4G27830.2" "AT4G27830.1" "AT5G46260.1" "AT2G32710.2"

Understanding the Gene Identifier “AT1G76820.1”

The nomenclature “AT1G76820.1” is commonly used in genomic data to denote gene identifiers in various databases. In this case, it is a nomenclature from the TAIR (The Arabidopsis Information Resource) database. Here is a breakdown of this identifier:

1.  AT: Indicates that the identifier refers to the plant Arabidopsis thaliana (always specified when referring to Arabidopsis).
2.  1: Refers to the chromosome on which the gene is located. In this case, it is the first chromosome.
3.  G76820: This is a unique gene number on this chromosome.
4.  .1: Version of the gene annotation. In this case, it is the first version of the annotation for this gene. Sometimes, additional versions are indicated as .2, .3, etc., if the annotation has been updated.

Filtering out only the significant results

# Отфильтровываем только значимые результаты
sign_results <- res %>%
  as.data.frame %>%
  rownames_to_column("gene_name") %>%
  mutate(gene_name = gsub("\\.\\d+$", "", gene_name)) %>%
  filter(padj < .05)

sign_results

Genes that increase and decrease expression are considered separately

sign_up <- sign_results %>% filter(log2FoldChange > 0)
sign_dw <- sign_results %>% filter(log2FoldChange < 0)

Calculating GO enrichment

This function performs Gene Ontology (GO) enrichment analysis. It tests whether the genes in your input list are overrepresented in specific GO categories compared to a background gene set. The plot will display the top 20 Biological Process (BP) GO terms that are significantly enriched in your list of genes. Each dot represents a GO term, with the size and color typically indicating the significance of the enrichment.

GO_enrich <- enrichGO(sign_up$gene_name, "org.At.tair.db", keyType = "TAIR", ont = "BP")
plt <- dotplot(GO_enrich, showCategory = 20)
plt + theme(
  axis.text.y = element_text(size = 6)
)

The top GO terms suggest that your gene set is significantly associated with processes related to amino acid metabolism, response to stress signals like jasmonic acid, and various biosynthetic pathways.

GO enricment table

GO_enrich@result
GO_enrich <- enrichplot::pairwise_termsim(GO_enrich)
plt <- emapplot(GO_enrich, 
                repel = TRUE, 
                showCategory = 12, 
                cluster.params = list(label_style = list(size = 3)))

plt

goplot(GO_enrich)
Warning: ggrepel: 3 unlabeled data points (too many overlaps). Consider increasing max.overlaps

FGSEA

GSEA is a method used in genomics to determine whether a set of genes (a gene set) shows statistically significant, concordant differences between two biological states.

How It Works?

1.  **Ranking Genes:** FGSEA begins by ranking genes based on their association with a particular phenotype or condition. This is often done using metrics such as fold change or t-statistics from differential expression analysis.
2.  **Enrichment Score Calculation:** It calculates an enrichment score for each gene set by examining how the genes in the set are distributed within the ranked list. It uses a fast algorithm to estimate the enrichment score, which reflects the concentration of genes from the set at the top or bottom of the ranked list.
3.  **Statistical Significance:** FGSEA performs a permutation test to assess the statistical significance of the enrichment scores, providing p-values that indicate whether the observed enrichment is greater than what would be expected by chance.

Downloading .gmt file

pathway <- fgsea::gmtPathways('wikipathways-20240410-gmt-Arabidopsis_thaliana.gmt')

Creating ranks and a dictionary for translating rank names

translated_names <- res %>% 
  as.data.frame() %>% 
  na.omit() %>%
  rownames_to_column("gene_name") %>%
  mutate(gene_name = gsub("\\.\\d+$", "", gene_name)) %>%
  pull(gene_name) %>% 
  bitr('TAIR', c("GENENAME", "ENTREZID"), 'org.At.tair.db') %>% 
  distinct(TAIR, .keep_all = T)
'select()' returned 1:many mapping between keys and columns
Warning in bitr(., "TAIR", c("GENENAME", "ENTREZID"), "org.At.tair.db") :
  68.98% of input gene IDs are fail to map...

Сreating a rank vector

ranks_for_gsea <- res %>% 
  as.data.frame() %>%   
  na.omit() %>% 
  arrange(desc(stat)) %>% 
  rownames_to_column("gene_name") %>%
  mutate(TAIR = gsub("\\.\\d+$", "", gene_name)) %>% 
  left_join(translated_names) %>% 
  mutate(NAME = ifelse(is.na(ENTREZID), TAIR, ENTREZID)) %>% 
  transmute(NAME, stat) %>% 
  deframe()
Joining with `by = join_by(TAIR)`
head(ranks_for_gsea, 100)
AT2G42640 AT1G07050    827377    827377 AT2G27810 AT4G31980    843133 AT1G17665 AT3G07090 AT5G59830    832706 AT4G38250 AT5G48250 
20.246724 11.120257  8.986663  8.053232  7.475392  7.469084  7.378915  7.096614  6.665295  6.529442  6.291401  6.282042  6.268846 
   835868    817745 AT2G29340 AT1G04620    836062 AT4G19520 AT5G23240    826716    837158 AT1G01240    844228    826983 AT2G43850 
 6.088399  6.006504  5.921277  5.909854  5.906834  5.861006  5.789372  5.784426  5.712031  5.493775  5.491014  5.484837  5.410686 
AT1G76790 AT5G05670 AT4G30310 AT5G35735    820771 AT5G38420 AT2G21530    831059    841749 AT4G03820    836034 AT2G43945    828419 
 5.390705  5.348861  5.346896  5.293781  5.256045  5.247263  5.237702  5.234711  5.211179  5.206994  5.169796  5.141525  5.126750 
AT4G12830    839924    835567 AT3G28460    817513 AT1G43670 AT5G09850 AT4G00165 AT4G16146 AT2G24600    838591    825880 AT5G53220 
 5.124072  5.116142  5.110733  5.104006  5.058099  5.048352  5.037742  5.000387  4.983393  4.921529  4.902252  4.886903  4.874522 
AT3G63160    814915 AT2G37020 AT5G43880    830548    814835 AT1G61430 AT4G02530 AT5G01660 AT3G22790    824525 AT1G25150    831201 
 4.872462  4.871772  4.867801  4.835534  4.833661  4.812673  4.802786  4.799946  4.796065  4.774055  4.768328  4.762493  4.761245 
AT4G18240    819244 AT2G33490    825503 AT1G23040 AT5G38460    842157    822537 AT3G47800    828777 AT5G02950 AT1G17610    819989 
 4.749131  4.737943  4.709552  4.662044  4.658823  4.632480  4.628964  4.597351  4.573431  4.567163  4.552039  4.539813  4.533890 
AT5G50565    824661    839921 AT2G27080 AT4G31880 AT5G19140 AT5G62720 AT4G17100    817112 AT5G04460    838301 AT2G30480 AT4G26670 
 4.520138  4.511153  4.475071  4.470800  4.448872  4.447919  4.418118  4.373725  4.371476  4.358213  4.356436  4.353084  4.349306 
AT2G22980 AT3G03770 AT2G19930    818723 AT4G32340 AT3G48740 AT5G62360    835938 AT1G12750 
 4.338115  4.336853  4.336747  4.333774  4.318183  4.308816  4.303773  4.301866  4.295312 

FGSEA calculating

fgsea_results <- fgsea::fgseaMultilevel(pathway, ranks_for_gsea)
Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam,  :
  There are ties in the preranked stats (0.09% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam,  :
  There are duplicate gene names, fgsea may produce unexpected results.
head(fgsea_results[order(pval), ])

GSEA plot for one path

fgsea::plotEnrichment(pathway[["Seed development%WikiPathways_20240410%WP2279%Arabidopsis thaliana"]], ranks_for_gsea) + labs(title="Seed development")

Drawing the top 10 most enriched paths from the top and bottom of the ranked list

topPathwaysUp <- fgsea_results[ES > 0][head(order(pval), n=10), pathway]
topPathwaysDown <- fgsea_results[ES < 0][head(order(pval), n=10), pathway]
topPathways <- c(topPathwaysUp, rev(topPathwaysDown))
fgsea::plotGseaTable(pathway[topPathways], ranks_for_gsea, fgsea_results, 
                     gseaParam=0.5)

FGSEA by clusterProfiler

GO_gsea <- gseGO(ranks_for_gsea, ont = "ALL", 'org.At.tair.db', eps = 0)
using 'fgsea' for GSEA analysis, please cite Korotkevich et al (2019).

preparing geneSet collections...
GSEA analysis...
Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam,  :
  There are ties in the preranked stats (0.09% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam,  :
  There are duplicate gene names, fgsea may produce unexpected results.
leading edge analysis...
done...

Ridge plot

plt <- ridgeplot(GO_gsea, showCategory = 20)
plt + theme(
  axis.text.y = element_text(size = 8)
)
Picking joint bandwidth of 0.248

Some of the paths can be related to plant wounding and how plants respond to injury or stress:

  1. Transporter Activity:
    • Active transmembrane transporter activity and related terms involve the movement of molecules across cell membranes. When a plant is wounded, it may need to transport defensive compounds, signaling molecules, or nutrients to and from the site of injury.
  2. Defense Response to Other Organism:
    • This term directly relates to how plants defend themselves against herbivores, pathogens, or other threats that could cause wounding. Plants often initiate defense mechanisms, including the production of secondary metabolites and signaling compounds, in response to wounding.
  3. Protein Modification Process:
    • Protein modification processes are crucial in the plant’s response to wounding. For example, post-translational modifications of proteins can be involved in signaling pathways that activate defense mechanisms.
  4. Binding Activities:
    • Anion binding, purine nucleotide binding, and similar terms may be involved in the recognition and response to stress signals. These binding activities can affect how plants perceive and react to wounding.
  5. Response to Inorganic Substance:
    • This could relate to how plants respond to changes in ion concentrations or other inorganic substances released or mobilized during wounding.
  6. Vacuole and Chloroplast Envelope:
    • Cellular compartments like the vacuole and chloroplast envelope may play roles in the storage and release of compounds related to the wound response. For instance, vacuoles can store defensive compounds or signaling molecules.
  7. Lipid Metabolic Process:
    • Lipid metabolism is often involved in the synthesis of signaling molecules like jasmonic acid, which is crucial for the wound response in plants.
  8. Defense and Stress Responses:
    • Terms related to defense responses and stress responses are particularly relevant to wounding. Plants activate various signaling pathways and produce protective compounds in response to physical damage.
gseaplot(GO_gsea, 1, title = GO_gsea@result$Description[[1]])

LS0tCnRpdGxlOiAiV291bmRfU2lnbmFsaW5nX0FyYWJpZG9wc2lzIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCiMjIFRyYW5zY3JpcHRvbWUgb2YgNS13ZWVrLW9sZCBDb2wtMCBhbmQgaXNpMS0yIGRpc3RhbCBsZWF2ZXMgMTMgaW4gdW50cmVhdGVkIGNvbnRyb2xzIG9yIHVwb24gd291bmRpbmcgbGVhdmUgOCMjCkRhdGEgZnJvbSBodHRwczovL3d3dy5uY2JpLm5sbS5uaWguZ292L2dlby9xdWVyeS9hY2MuY2dpP2FjYz1HU0UxNTc5MzgKCUluIHRoYXQgc3R1ZHksIElNUEFJUkVEIFNVQ1JPU0UgSU5EVUNUSU9OIDEgKElTSTEpIHdhcyBpZGVudGlmaWVkIGFzIGEgcGxheWVyIGluIGxvbmcgZGlzdGFuY2Ugd291bmQgc2lnbmFsaW5nIGluIEFyYWJpZG9wc2lzLiBUbyBmdXJ0aGVyIGFzc2VzcyB0aGUgaW1wYWN0IG9mIElTSTEgb24gdGhlIHdvdW5kIHJlc3BvbnNlLCBhdXRob3JzIHRlc3RlZCB0aGUgdHJhbnNjcmlwdG9tZXMgb2YgdGhlIHdvdW5kZWQgaXNpMS0yIG11dGFudHMgaW4gY29tcGFyaXNvbiB3aXRoIHdvdW5kZWQgd2lsZCB0eXBlIHBsYW50cywgaW4gb3JkZXIgdG8gZmluZCBnZW5lcyB0aGF0IHdlcmUgZGVyZWd1bGF0ZWQgaW4gaXNpMSBsb3NzLW9mLWZ1bmN0aW9uIG11dGFudHMuXG4KCioqVHdvIGdyb3VwcyBvZiBwbGFudHM6KiogY29udHJvbCAoQ29sLTApIGFuZCBpc2ktbXV0YW50IHBsYW50cyAoaXNpMS0yKSB3aXRoIHRocmVlIGJpb2xvZ2ljYWwgcmVwbGljYXRlcyBwZXIgZ3JvdXA7IERpc3RhbCBsZWF2ZXMgMTMgd2VyZSBjb2xsZWN0ZWQgb25lIGhvdXIgYWZ0ZXIgd291bmRpbmcgbGVhdmUgOCAoaW4gd291bmRlZCBwbGFudHMpIG9yIHdpdGhvdXQgYW55IHRyZWF0bWVudCAodW53b3VuZGVkIHBsYW50cykuIFR3byBpbmRpdmlkdWFsIHBsYW50cyB3ZXJlIHBvb2xlZCBmb3Igb25lIHJlcGxpY2F0ZTsgc2luZ2xlIHJlYWQgZGVzaWduLgoKU2V0IHlvdXIgd29ya2luZyBkaXJlY3Rvcnkgd2l0aCBLYWxsaXN0byByZXN1bHRzCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19rbml0JHNldChyb290LmRpciA9ICJ+L0dpdEh1Yi9STkFzZXFfcHJvamVjdHMvV291bmRfU2lnbmFsaW5nX0FyYWJpZG9wc2lzL3Jlc3VsdHMvIikKYGBgCkNoZWNraW5nIGZvciByZXF1aXJlZCBwYWNrYWdlcyBhbmQgaW5zdGFsbCwgaWYgbmVjZXNzYXJ5CmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeSh0eGltcG9ydCkKbGlicmFyeShERVNlcTIpCmxpYnJhcnkocGhlYXRtYXApCmxpYnJhcnkoUkNvbG9yQnJld2VyKQpsaWJyYXJ5KHJoZGY1KQpsaWJyYXJ5KFdHQ05BKQpsaWJyYXJ5KGNsdXN0ZXJQcm9maWxlcikKbGlicmFyeShvcmcuQXQudGFpci5kYikKbGlicmFyeShnZ3JpZGdlcykKYGBgCiMjIyBJbXBvcnRpbmcgVHJhbnNjcmlwdC1MZXZlbCBRdWFudGlmaWNhdGlvbiBEYXRhIGFuZCBjcmVhdGluZyBERVNlcTIgRGF0YXNldCAjIyMKYGBge3J9CnNhbXBsZXMgPC0gcmVhZF90c3YoInBoZW5vdGFibGUudHN2Iiwgc2hvd19jb2xfdHlwZXMgPSBGQUxTRSkKc2FtcGxlcwpgYGAKYGBge3J9CmZpbGVzIDwtIGZpbGUucGF0aChzYW1wbGVzJHBhdGgsICJhYnVuZGFuY2UuaDUiKSAgIyBwYXRoIHRvIGFidW5kYW5jZSBmaWxlcyBpbiBrYWxsaXN0byBkaXJzCmZpbGVzCmBgYApUaGUgZGF0YSBpcyBmcm9tIEthbGxpc3RvLCBhIHRvb2wgZm9yIHF1YW50aWZ5aW5nIFJOQS1zZXEgZGF0YSBhdCB0aGUgdHJhbnNjcmlwdCBsZXZlbC4KCeKAogl0eGltcG9ydDogSW1wb3J0cyB0cmFuc2NyaXB0LWxldmVsIHF1YW50aWZpY2F0aW9uIGRhdGEgZnJvbSBLYWxsaXN0by4KCeKAoglERVNlcURhdGFTZXRGcm9tVHhpbXBvcnQ6IENvbnZlcnRzIHRoZSBpbXBvcnRlZCBkYXRhIGludG8gYSBERVNlcTIgZGF0YXNldCwgc2V0dGluZyB1cCBmb3IgZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gYW5hbHlzaXMuCgnigKIJZGRzVHhpOiBDb250YWlucyB0aGUgREVTZXEyIGRhdGFzZXQgb2JqZWN0IHdoaWNoIGluY2x1ZGVzIHRoZSBjb3VudCBkYXRhLCBzYW1wbGUgbWV0YWRhdGEsIGFuZCBkZXNpZ24gZm9ybXVsYS4KYGBge3J9CnR4aSA8LSB0eGltcG9ydChmaWxlcywgdHlwZSA9ICdrYWxsaXN0bycsIHR4T3V0ID0gVCkKZGRzVHhpIDwtIERFU2VxRGF0YVNldEZyb21UeGltcG9ydCh0eGksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sRGF0YSA9IHNhbXBsZXMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVzaWduID0gfiBnZW5vdHlwZSpjb25kaXRpb24pIApkZHNUeGkKYGBgCioqRmlsdGVyIExvdy1FeHByZXNzaW9uIEdlbmVzIGFuZCByZWxldmVsIHRoZSBnZW5vdHlwZSBGYWN0b3IqKgpUaGUgY29kZSBrZWVwcyBvbmx5IHRob3NlIGdlbmVzIHdoZXJlIHRoZSBzdW0gb2YgY291bnRzIGFjcm9zcyBhbGwgc2FtcGxlcyBpcyBhdCBsZWFzdCAxMAoncmVsZXZlbCcgY2hhbmdlcyB0aGUgcmVmZXJlbmNlIGxldmVsIG9mIHRoZSBnZW5vdHlwZSBmYWN0b3IgdG8gZW5zdXJlcyB0aGF0IGFsbCBjb21wYXJpc29ucyBvZiBnZW5vdHlwZSBlZmZlY3RzIGFyZSBtYWRlIHJlbGF0aXZlIHRvIHRoZSDigJxXVOKAnSBnZW5vdHlwZS4KYGBge3J9CmRkcyA8LSBkZHNUeGlbcm93U3Vtcyhjb3VudHMoZGRzVHhpKSkgPj0gMTAsXQpkZHMkZ2Vub3R5cGUgPC0gcmVsZXZlbChkZHMkZ2Vub3R5cGUsIHJlZiA9ICJXVCIpCmBgYAojIyMgIFJ1biBEaWZmZXJlbnRpYWwgRXhwcmVzc2lvbiBBbmFseXNpcyAjIyMKYGBge3J9CmRkcyA8LSBERVNlcShkZHMsIGZpdFR5cGUgPSAnbG9jYWwnKQpkZHMKYGBgCioqVmFyaWFuY2Utc3RhYmlsaXppbmcgdHJhbnNmb3JtYXRpb24gb2YgZGF0YSAqKgpUaGUgVlNUIGFpbXMgdG8gc3RhYmlsaXplIHRoZSB2YXJpYW5jZSBhY3Jvc3MgdGhlIHJhbmdlIG9mIG1lYW4gZXhwcmVzc2lvbiB2YWx1ZXMsIG1ha2luZyB0aGUgZGF0YSBtb3JlIHN1aXRhYmxlIGZvciBkb3duc3RyZWFtIGFuYWx5c2VzIHN1Y2ggYXMgY2x1c3RlcmluZyBvciBwcmluY2lwYWwgY29tcG9uZW50IGFuYWx5c2lzIChQQ0EpLgpibGluZCA9IEZBTFNFOiBUaGlzIGFyZ3VtZW50IGNvbnRyb2xzIHdoZXRoZXIgdGhlIHRyYW5zZm9ybWF0aW9uIHNob3VsZCBiZSBwZXJmb3JtZWQgd2l0aG91dCBhY2NvdW50aW5nIGZvciB0aGUgZXhwZXJpbWVudGFsIGRlc2lnbi4gU2V0dGluZyBibGluZCA9IEZBTFNFIG1lYW5zIHRoYXQgdGhlIHRyYW5zZm9ybWF0aW9uIHdpbGwgdXNlIHRoZSBpbmZvcm1hdGlvbiBmcm9tIHRoZSBleHBlcmltZW50YWwgZGVzaWduIChpLmUuLCBpdCB3aWxsIG5vdCDigJxibGluZOKAnSB0byB0aGUgZGVzaWduKSwgd2hpY2ggaXMgb2Z0ZW4gcHJlZmVycmVkIHdoZW4geW91IGFyZSBpbnRlcmVzdGVkIGluIHByZXNlcnZpbmcgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGNvbmRpdGlvbnMgaW4gdGhlIHRyYW5zZm9ybWVkIGRhdGEuCmZpdFR5cGUgPSAnbG9jYWwnOiBTcGVjaWZpZXMgdGhlIG1ldGhvZCBmb3IgZXN0aW1hdGluZyB0aGUgZGlzcGVyc2lvbiB1c2VkIGluIHRoZSB0cmFuc2Zvcm1hdGlvbi4gVGhlICdsb2NhbCcgb3B0aW9uIGZpdHMgYSBsb2NhbCBzbW9vdGhpbmcgc3BsaW5lIHRvIHRoZSBkaXNwZXJzaW9uIGVzdGltYXRlcywgd2hpY2ggY2FuIHByb3ZpZGUgYSBiZXR0ZXIgZml0IGZvciBkYXRhc2V0cyB3aXRoIHZhcnlpbmcgZGlzcGVyc2lvbiB2YWx1ZXMuIChpdCBjYW4gcnVuIHdpdGhvdXQgYW55IGZpdCB0eXBlIGFuZCBzZXQgaXQgYXV0b21hdGljYWxseSkKYGBge3J9CnZzZCA8LSB2c3QoZGRzLCBibGluZCA9IEZBTFNFLCBmaXRUeXBlID0gJ2xvY2FsJykKdnNkCmBgYApMZXQncyBsb29rIGF0IHRoZSByZXN1bHRzOgpgYGB7cn0KcmVzIDwtIHJlc3VsdHMoZGRzKQpyZXMgCmBgYAoJ4oCiCUJhc2UgTWVhbiBwcm92aWRlcyB0aGUgYXZlcmFnZSBleHByZXNzaW9uIGxldmVsLgoJ4oCiCUxvZzIgRm9sZCBDaGFuZ2UgaW5kaWNhdGVzIGhvdyB0aGUgZXhwcmVzc2lvbiBjaGFuZ2VzIGJldHdlZW4gY29uZGl0aW9ucy4KCeKAoglMZmNTRSBnaXZlcyB0aGUgdmFyaWFiaWxpdHkgaW4gdGhlIGxvZzIgZm9sZCBjaGFuZ2UgZXN0aW1hdGUuCgnigKIJU3RhdCBpcyB0aGUgV2FsZCBzdGF0aXN0aWMgdXNlZCBpbiBoeXBvdGhlc2lzIHRlc3RpbmcuCgkKQW5kIGhvdyBtYW55IG9mIHRoZXNlIHJlc3VsdHMgYXJlIHNpZ25pZmljYW50PwpgYGB7cn0KcmVzMDA1IDwtIHJlc3VsdHMoZGRzLCBhbHBoYT0wLjA1KQpzdW1tYXJ5KHJlczAwNSkKYGBgClRoaXMgbWVhbnMgdGhhdCBvdXQgb2YgMzcsNDY1IGdlbmVzIHRlc3RlZCwgMyw0NTggd2VyZSBpZGVudGlmaWVkIGFzIHNpZ25pZmljYW50IHdpdGggYSBwYWRqIGxlc3MgdGhhbiAwLjA1LiBUaGUgcmVtYWluaW5nIGdlbmVzIGRpZCBub3QgcGFzcyB0aGlzIHRocmVzaG9sZCBhbmQgYXJlIGNvbnNpZGVyZWQgaW5zaWduaWZpY2FudC4KCkxldCdzIGxvb2sgb24gbmFtZXMgb2Ygb3VyIHZhcmlhYmxlczoKYGBge3J9CnJlc3VsdHNOYW1lcyhkZHMpCmBgYApJbnRlcmNlcHQgPSBnZW5vdHlwZVdULmNvbmRpdGlvblVXLiBJbiB0aGlzIG1vZGVsLCB0aGUgaW50ZXJjZXB0IHJlcHJlc2VudHMgdGhlIGJhc2VsaW5lIGdlbmUgZXhwcmVzc2lvbiBmb3IgdGhlIHJlZmVyZW5jZSBsZXZlbHMgb2YgYm90aCBnZW5vdHlwZSBhbmQgY29uZGl0aW9uLgpMZXQncyBhcnJhbmdlZCBpdCBieSBsb2cyRm9sZENoYW5nZToKYGBge3J9Cm9yZGVyX2luZGljZXMgPC0gb3JkZXIoLXJlcyRsb2cyRm9sZENoYW5nZSkKcmVzX3NvcnRlZCA8LSByZXNbb3JkZXJfaW5kaWNlcywgXQpyZXNfc29ydGVkCmBgYApWaXN1YWxpc2F0aW9uIGZvciB0aGUgZmlyc3QgZ2VuZQpgYGB7cn0KIyBHZW5lIGNvdW50cyBmb3IgYSBzcGVjaWZpYyBnZW5lCnBsb3RDb3VudHMoZGRzLCBnZW5lPSJBVDFHMTA0MzAuMSIsIGludGdyb3VwPSJnZW5vdHlwZSIpCnBsb3RDb3VudHMoZGRzLCBnZW5lPSJBVDFHMTA0MzAuMSIsIGludGdyb3VwPSJjb25kaXRpb24iKQpgYGAKKipWb2xrYW5vIHBsb3QqKgpgYGB7cn0KcmVzICU+JQogIGFzLmRhdGEuZnJhbWUgJT4lIAogIGZpbHRlcighaXMubmEobG9nMkZvbGRDaGFuZ2UpLCAhaXMubmEocGFkaiksIGxvZzJGb2xkQ2hhbmdlID49IC0yLjUsIGxvZzJGb2xkQ2hhbmdlIDw9IDIuNSkgJT4lCiAgZ2dwbG90KGFlcyhsb2cyRm9sZENoYW5nZSwgLWxvZzEwKHBhZGopLCBjb2xvciA9IHBhZGogPCAwLjA1KSkgKwogIGdlb21fcG9pbnQoKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCJibGFjayIsICJyZWQiKSkgKwogIHhsaW0oYygtMi41LCAyLjUpKQpgYGAKKiogUENBIHBsb3QgKioKYGBge3J9CnBsb3RQQ0EodnNkLCBpbnRncm91cD1jKCJnZW5vdHlwZSIsICJjb25kaXRpb24iKSkKYGBgCklkZWFsbHksIGVhY2ggZ3JvdXAgb2YgcmVwbGljYXRlcyBzaG91bGQgY2x1c3RlciB0b2dldGhlciBpbiBhIFBDQSBwbG90LCByZWZsZWN0aW5nIHNpbWlsYXIgZ2VuZSBleHByZXNzaW9uIHByb2ZpbGVzIHdpdGhpbiBlYWNoIGdyb3VwLiAKLSAqKk91dGxpZXIgaW4gdGhlIGBJU0k6VVdgIEdyb3VwKio6IFRoZSBmYWN0IHRoYXQgb25lIHJlcGxpY2F0ZSBmcm9tIHRoZSBgSVNJOlVXYCBncm91cCBjbHVzdGVycyBjbG9zZXIgdG8gdGhlIGBXVDpVV2AgZ3JvdXAgY291bGQgc3VnZ2VzdCB0aGF0IHRoZSBJU0kxIGxvc3Mtb2YtZnVuY3Rpb24gbXV0YXRpb24gd2FzIG5vdCBmdWxseSBwZW5ldHJhbnQgb3IgZGlkIG5vdCBtYW5pZmVzdCBhcyBzdHJvbmdseSBpbiB0aGF0IHBhcnRpY3VsYXIgcmVwbGljYXRlLiBBcyBhIHJlc3VsdCwgaXRzIGdlbmUgZXhwcmVzc2lvbiBwcm9maWxlIGlzIG1vcmUgc2ltaWxhciB0byB0aGUgd2lsZC10eXBlIHVud291bmRlZCAoYFdUOlVXYCkgY29uZGl0aW9uIHJhdGhlciB0aGFuIHRvIGl0cyBpbnRlbmRlZCBncm91cCAoYElTSTpVV2ApLgoKICAtIFRoaXMgY291bGQgb2NjdXIgaWYgdGhlIG11dGF0aW9uIGluIElTSTEgaXMgdmFyaWFibGUgaW4gaXRzIGVmZmVjdCBvciBpZiB0aGVyZSB3YXMgc29tZSB0ZWNobmljYWwgb3IgYmlvbG9naWNhbCByZWFzb24gd2h5IHRoaXMgcmVwbGljYXRlIGRpZCBub3QgZXhoaWJpdCB0aGUgZXhwZWN0ZWQgbXV0YW50IHBoZW5vdHlwZS4gCgotICoqQ2xlYXIgRGl2aXNpb24gQmV0d2VlbiBgV2AgYW5kIGBVV2AgR3JvdXBzKio6IFRoZSBkaXN0aW5jdCBzZXBhcmF0aW9uIG9mIHRoZSB3b3VuZGVkIChgV2ApIGFuZCB1bndvdW5kZWQgKGBVV2ApIHNhbXBsZXMgb24gdGhlIFBDQSBwbG90IGluZGljYXRlcyB0aGF0IHRoZSB3b3VuZGluZyBoYXMgYSBzdHJvbmcgYW5kIGNvbnNpc3RlbnQgZWZmZWN0IG9uIGdlbmUgZXhwcmVzc2lvbiwgcmVnYXJkbGVzcyBvZiBnZW5vdHlwZS4gCgoqKiBNQSBwbG90ICoqCgpVbmRlciBhIG51bGwgaHlwb3RoZXNpcyBvZiBubyBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiwgbW9zdCBnZW5lcycgbG9nMiBmb2xkIGNoYW5nZXMgc2hvdWxkIGNlbnRlciB0aWdodGx5IGFyb3VuZCAwLiBIb3dldmVyLCBnZW5lcyB3aXRoIGhpZ2hlciBhYnNvbHV0ZSBNIHZhbHVlcyBleGhpYml0IGdyZWF0ZXIgZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gYmV0d2VlbiBjb25kaXRpb25zLiBBbiBpZGVhbCBNQSBwbG90IHdpbGwgc2hvdyB0aGUgbWFqb3JpdHkgb2YgZ2VuZXMgYWxvbmcgTT0wIGFuZCBvdXRsaWVycyBzdHJldGNoaW5nIHRvd2FyZHMgdGhlIGdyYXBoIHBlcmlwaGVyaWVzLiAKYGBge3J9CnBsb3RNQShkZHMpCmBgYApIZXJlIHRoZSBkaWZmZXJlbmNlIGluIGV4cHJlc3Npb24gb2YgdGhlIGVudGlyZSBtb2RlbCBvZiBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBpcyBzaG93biBhbmQgd2Ugc2VlIHRoYXQgdGhlcmUgYXJlIG5vdCBtYW55IGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBnZW5lcyBhbmQgc29tZSBncm91cHMgYXJlIG5vdGljZWFibGUgaW4gdGhlIGdyYXBoLiBMZXQncyBkaXZpZGUgdGhpcyBncmFwaCBieSBjb25kaXRpb25zIGFuZCBsb29rIGF0IGl0IHNlcGFyYXRlbHkuCioqV291bmRlZCBWUyBVbndvdW5lZCoqCmBgYHtyfQpyZXMgPC0gcmVzdWx0cyhkZHMsIGNvbnRyYXN0PWMoImNvbmRpdGlvbiIsICJXIiwgIlVXIikpCnBsb3RNQShyZXMpCmBgYApUaGlzIHBsb3QgbG9va3MgbW9yZSBsaWtlIGFuIGlkZWFsIE1BIGdyYXBoIHdpdGggYSBsYXJnZSBudW1iZXIgb2YgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGdlbmVzLgpXaGF0IGFib3V0IElTSTEtbXV0YXRlZCBWUyBXVD8KYGBge3J9CnJlcyA8LSByZXN1bHRzKGRkcywgY29udHJhc3Q9YygiZ2Vub3R5cGUiLCAiSVNJIiwgIldUIikpCnBsb3RNQShyZXMpCmBgYApUaGlzIHBsb3QgYXBwZWFycyB0byBiZSBjbG9zZSB3aXRoIHRoZSBudWxsIGh5cG90aGVzaXMsIGFuZCByZXZlYWxzIHNtYWxsIGVmZmVjdCBvZiB0aGUgZ2Vub3R5cGUuCioqUGxvdCBhIGhlYXRtYXAgb2YgMTAwIG1vc3QgZXhwcmVzc2VkIGdlbmVzKioKYGBge3J9CnNlbGVjdCA8LSBvcmRlcihyb3dNZWFucyhjb3VudHMoZGRzLG5vcm1hbGl6ZWQ9VFJVRSkpLAogICAgICAgICAgICAgICAgZGVjcmVhc2luZz1UUlVFKVsxOjEwMF0KZGYgPC0gYXMuZGF0YS5mcmFtZShjb2xEYXRhKGRkcylbLGMoImdlbm90eXBlIiwgImNvbmRpdGlvbiIpXSkKcGhlYXRtYXAoYXNzYXkodnNkKVtzZWxlY3QsXSwgCiAgICAgICAgIGNsdXN0ZXJfcm93cyA9IFRSVUUsIAogICAgICAgICBzaG93X3Jvd25hbWVzID0gVFJVRSwgCiAgICAgICAgIGNsdXN0ZXJfY29scyA9IFRSVUUsIAogICAgICAgICBhbm5vdGF0aW9uX2NvbCA9IGRmLAogICAgICAgICBmb250c2l6ZV9yb3cgPSA2KSAgIyBBZGp1c3QgZm9udHNpemVfcm93IHRvIHlvdXIgcHJlZmVyZW5jZQpgYGAKV2UgaGF2ZSBhIGRpc3RpbmN0IHNlcGFyYXRpb24gb2YgdGhlIHdvdW5kZWQgKGBXYCkgYW5kIHVud291bmRlZCAoYFVXYCkgc2FtcGxlcyBhZ2Fpbiwgd2hpY2ggaW5kaWNhdGVzIHRoYXQgdGhlIHdvdW5kaW5nIGhhcyBhIHN0cm9uZyBhbmQgY29uc2lzdGVudCBlZmZlY3Qgb24gZ2VuZSBleHByZXNzaW9uLCByZWdhcmRsZXNzIG9mIGdlbm90eXBlLiAKCioqUGxvdCBvZiB0aGUgZGlzdGFuY2UgYmV0d2VlbiBzYW1wbGVzIGhlYXRtYXAqKgpgYGB7cn0Kc2FtcGxlRGlzdHMgPC0gZGlzdCh0KGFzc2F5KHZzZCkpKQpzYW1wbGVEaXN0TWF0cml4IDwtIGFzLm1hdHJpeChzYW1wbGVEaXN0cykKcm93bmFtZXMoc2FtcGxlRGlzdE1hdHJpeCkgPC0gcGFzdGUodnNkJGdlbm90eXBlLCB2c2QkY29uZGl0aW9uLCBzZXA9Ii0iKQpjb2xuYW1lcyhzYW1wbGVEaXN0TWF0cml4KSA8LSBwYXN0ZSh2c2QkZ2Vub3R5cGUsIHZzZCRjb25kaXRpb24sIHNlcD0iLSIpCmNvbG9ycyA8LSBjb2xvclJhbXBQYWxldHRlKCByZXYoYnJld2VyLnBhbCg5LCAiQmx1ZXMiKSkgKSgyNTUpCnBoZWF0bWFwKHNhbXBsZURpc3RNYXRyaXgsCiAgICAgICAgIGNsdXN0ZXJpbmdfZGlzdGFuY2Vfcm93cz1zYW1wbGVEaXN0cywKICAgICAgICAgY2x1c3RlcmluZ19kaXN0YW5jZV9jb2xzPXNhbXBsZURpc3RzLAogICAgICAgICBjb2xvciA9IGNvbG9ycykKYGBgClNhbWUgc2VwYXJhdGlvbiBvZiB0aGUgd291bmRlZCAoYFdgKSBhbmQgdW53b3VuZGVkIChgVVdgKSBzYW1wbGVzIGFnYWluCgojIyMg0JDQvdCw0LvQuNC3INC+0LHQvtCz0LDRidC10L3QuNGPICMjIwpgYGB7cn0KcmVzCnN1bW1hcnkocmVzKQpgYGAKYGBge3J9CmdlbmVfaWRzIDwtIHJvd25hbWVzKHJlcykKaGVhZChnZW5lX2lkcywgOTkpCmBgYAoqKlVuZGVyc3RhbmRpbmcgdGhlIEdlbmUgSWRlbnRpZmllciDigJxBVDFHNzY4MjAuMeKAnSoqCgpUaGUgbm9tZW5jbGF0dXJlIOKAnEFUMUc3NjgyMC4x4oCdIGlzIGNvbW1vbmx5IHVzZWQgaW4gZ2Vub21pYyBkYXRhIHRvIGRlbm90ZSBnZW5lIGlkZW50aWZpZXJzIGluIHZhcmlvdXMgZGF0YWJhc2VzLiBJbiB0aGlzIGNhc2UsIGl0IGlzIGEgbm9tZW5jbGF0dXJlIGZyb20gdGhlIFRBSVIgKFRoZSBBcmFiaWRvcHNpcyBJbmZvcm1hdGlvbiBSZXNvdXJjZSkgZGF0YWJhc2UuIEhlcmUgaXMgYSBicmVha2Rvd24gb2YgdGhpcyBpZGVudGlmaWVyOgoKCTEuCUFUOiBJbmRpY2F0ZXMgdGhhdCB0aGUgaWRlbnRpZmllciByZWZlcnMgdG8gdGhlIHBsYW50IEFyYWJpZG9wc2lzIHRoYWxpYW5hIChhbHdheXMgc3BlY2lmaWVkIHdoZW4gcmVmZXJyaW5nIHRvIEFyYWJpZG9wc2lzKS4KCTIuCTE6IFJlZmVycyB0byB0aGUgY2hyb21vc29tZSBvbiB3aGljaCB0aGUgZ2VuZSBpcyBsb2NhdGVkLiBJbiB0aGlzIGNhc2UsIGl0IGlzIHRoZSBmaXJzdCBjaHJvbW9zb21lLgoJMy4JRzc2ODIwOiBUaGlzIGlzIGEgdW5pcXVlIGdlbmUgbnVtYmVyIG9uIHRoaXMgY2hyb21vc29tZS4KCTQuCS4xOiBWZXJzaW9uIG9mIHRoZSBnZW5lIGFubm90YXRpb24uIEluIHRoaXMgY2FzZSwgaXQgaXMgdGhlIGZpcnN0IHZlcnNpb24gb2YgdGhlIGFubm90YXRpb24gZm9yIHRoaXMgZ2VuZS4gU29tZXRpbWVzLCBhZGRpdGlvbmFsIHZlcnNpb25zIGFyZSBpbmRpY2F0ZWQgYXMgLjIsIC4zLCBldGMuLCBpZiB0aGUgYW5ub3RhdGlvbiBoYXMgYmVlbiB1cGRhdGVkLgoJCioqRmlsdGVyaW5nIG91dCBvbmx5IHRoZSBzaWduaWZpY2FudCByZXN1bHRzKioKYGBge3J9CnNpZ25fcmVzdWx0cyA8LSByZXMgJT4lCiAgYXMuZGF0YS5mcmFtZSAlPiUKICByb3duYW1lc190b19jb2x1bW4oImdlbmVfbmFtZSIpICU+JQogIG11dGF0ZShnZW5lX25hbWUgPSBnc3ViKCJcXC5cXGQrJCIsICIiLCBnZW5lX25hbWUpKSAlPiUKICBmaWx0ZXIocGFkaiA8IC4wNSkKCnNpZ25fcmVzdWx0cwpgYGAKR2VuZXMgdGhhdCBpbmNyZWFzZSBhbmQgZGVjcmVhc2UgZXhwcmVzc2lvbiBhcmUgY29uc2lkZXJlZCBzZXBhcmF0ZWx5CmBgYHtyfQpzaWduX3VwIDwtIHNpZ25fcmVzdWx0cyAlPiUgZmlsdGVyKGxvZzJGb2xkQ2hhbmdlID4gMCkKc2lnbl9kdyA8LSBzaWduX3Jlc3VsdHMgJT4lIGZpbHRlcihsb2cyRm9sZENoYW5nZSA8IDApCmBgYAoqKkNhbGN1bGF0aW5nIEdPIGVucmljaG1lbnQqKgoKVGhpcyBmdW5jdGlvbiBwZXJmb3JtcyBHZW5lIE9udG9sb2d5IChHTykgZW5yaWNobWVudCBhbmFseXNpcy4gSXQgdGVzdHMgd2hldGhlciB0aGUgZ2VuZXMgaW4geW91ciBpbnB1dCBsaXN0IGFyZSBvdmVycmVwcmVzZW50ZWQgaW4gc3BlY2lmaWMgR08gY2F0ZWdvcmllcyBjb21wYXJlZCB0byBhIGJhY2tncm91bmQgZ2VuZSBzZXQuClRoZSBwbG90IHdpbGwgZGlzcGxheSB0aGUgdG9wIDIwIEJpb2xvZ2ljYWwgUHJvY2VzcyAoQlApIEdPIHRlcm1zIHRoYXQgYXJlIHNpZ25pZmljYW50bHkgZW5yaWNoZWQgaW4geW91ciBsaXN0IG9mIGdlbmVzLgpFYWNoIGRvdCByZXByZXNlbnRzIGEgR08gdGVybSwgd2l0aCB0aGUgc2l6ZSBhbmQgY29sb3IgdHlwaWNhbGx5IGluZGljYXRpbmcgdGhlIHNpZ25pZmljYW5jZSBvZiB0aGUgZW5yaWNobWVudC4KYGBge3J9CkdPX2VucmljaCA8LSBlbnJpY2hHTyhzaWduX3VwJGdlbmVfbmFtZSwgIm9yZy5BdC50YWlyLmRiIiwga2V5VHlwZSA9ICJUQUlSIiwgb250ID0gIkJQIikKcGx0IDwtIGRvdHBsb3QoR09fZW5yaWNoLCBzaG93Q2F0ZWdvcnkgPSAyMCkKcGx0ICsgdGhlbWUoCiAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYpCikKCmBgYApUaGUgdG9wIEdPIHRlcm1zIHN1Z2dlc3QgdGhhdCB5b3VyIGdlbmUgc2V0IGlzIHNpZ25pZmljYW50bHkgYXNzb2NpYXRlZCB3aXRoIHByb2Nlc3NlcyByZWxhdGVkIHRvIGFtaW5vIGFjaWQgbWV0YWJvbGlzbSwgcmVzcG9uc2UgdG8gc3RyZXNzIHNpZ25hbHMgbGlrZSBqYXNtb25pYyBhY2lkLCBhbmQgdmFyaW91cyBiaW9zeW50aGV0aWMgcGF0aHdheXMuCgoqKkdPIGVucmljbWVudCB0YWJsZSoqCmBgYHtyfQpHT19lbnJpY2hAcmVzdWx0CmBgYApgYGB7cn0KR09fZW5yaWNoIDwtIGVucmljaHBsb3Q6OnBhaXJ3aXNlX3Rlcm1zaW0oR09fZW5yaWNoKQpwbHQgPC0gZW1hcHBsb3QoR09fZW5yaWNoLCAKICAgICAgICAgICAgICAgIHJlcGVsID0gVFJVRSwgCiAgICAgICAgICAgICAgICBzaG93Q2F0ZWdvcnkgPSAxMiwgCiAgICAgICAgICAgICAgICBjbHVzdGVyLnBhcmFtcyA9IGxpc3QobGFiZWxfc3R5bGUgPSBsaXN0KHNpemUgPSAzKSkpCgpwbHQKYGBgCgpgYGB7cn0KZ29wbG90KEdPX2VucmljaCkKYGBgCiMjIyBGR1NFQSAjIyMKCkdTRUEgaXMgYSBtZXRob2QgdXNlZCBpbiBnZW5vbWljcyB0byBkZXRlcm1pbmUgd2hldGhlciBhIHNldCBvZiBnZW5lcyAoYSBnZW5lIHNldCkgc2hvd3Mgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCwgY29uY29yZGFudCBkaWZmZXJlbmNlcyBiZXR3ZWVuIHR3byBiaW9sb2dpY2FsIHN0YXRlcy4KCioqSG93IEl0IFdvcmtzPyoqCgoJMS4JKipSYW5raW5nIEdlbmVzOioqIEZHU0VBIGJlZ2lucyBieSByYW5raW5nIGdlbmVzIGJhc2VkIG9uIHRoZWlyIGFzc29jaWF0aW9uIHdpdGggYSBwYXJ0aWN1bGFyIHBoZW5vdHlwZSBvciBjb25kaXRpb24uIFRoaXMgaXMgb2Z0ZW4gZG9uZSB1c2luZyBtZXRyaWNzIHN1Y2ggYXMgZm9sZCBjaGFuZ2Ugb3IgdC1zdGF0aXN0aWNzIGZyb20gZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gYW5hbHlzaXMuCgkyLgkqKkVucmljaG1lbnQgU2NvcmUgQ2FsY3VsYXRpb246KiogSXQgY2FsY3VsYXRlcyBhbiBlbnJpY2htZW50IHNjb3JlIGZvciBlYWNoIGdlbmUgc2V0IGJ5IGV4YW1pbmluZyBob3cgdGhlIGdlbmVzIGluIHRoZSBzZXQgYXJlIGRpc3RyaWJ1dGVkIHdpdGhpbiB0aGUgcmFua2VkIGxpc3QuIEl0IHVzZXMgYSBmYXN0IGFsZ29yaXRobSB0byBlc3RpbWF0ZSB0aGUgZW5yaWNobWVudCBzY29yZSwgd2hpY2ggcmVmbGVjdHMgdGhlIGNvbmNlbnRyYXRpb24gb2YgZ2VuZXMgZnJvbSB0aGUgc2V0IGF0IHRoZSB0b3Agb3IgYm90dG9tIG9mIHRoZSByYW5rZWQgbGlzdC4KCTMuCSoqU3RhdGlzdGljYWwgU2lnbmlmaWNhbmNlOioqIEZHU0VBIHBlcmZvcm1zIGEgcGVybXV0YXRpb24gdGVzdCB0byBhc3Nlc3MgdGhlIHN0YXRpc3RpY2FsIHNpZ25pZmljYW5jZSBvZiB0aGUgZW5yaWNobWVudCBzY29yZXMsIHByb3ZpZGluZyBwLXZhbHVlcyB0aGF0IGluZGljYXRlIHdoZXRoZXIgdGhlIG9ic2VydmVkIGVucmljaG1lbnQgaXMgZ3JlYXRlciB0aGFuIHdoYXQgd291bGQgYmUgZXhwZWN0ZWQgYnkgY2hhbmNlLgoKRG93bmxvYWRpbmcgLmdtdCBmaWxlCmBgYHtyfQpwYXRod2F5IDwtIGZnc2VhOjpnbXRQYXRod2F5cygnd2lraXBhdGh3YXlzLTIwMjQwNDEwLWdtdC1BcmFiaWRvcHNpc190aGFsaWFuYS5nbXQnKQpgYGAKCkNyZWF0aW5nIHJhbmtzIGFuZCBhIGRpY3Rpb25hcnkgZm9yIHRyYW5zbGF0aW5nIHJhbmsgbmFtZXMKYGBge3J9CnRyYW5zbGF0ZWRfbmFtZXMgPC0gcmVzICU+JSAKICBhcy5kYXRhLmZyYW1lKCkgJT4lIAogIG5hLm9taXQoKSAlPiUKICByb3duYW1lc190b19jb2x1bW4oImdlbmVfbmFtZSIpICU+JQogIG11dGF0ZShnZW5lX25hbWUgPSBnc3ViKCJcXC5cXGQrJCIsICIiLCBnZW5lX25hbWUpKSAlPiUKICBwdWxsKGdlbmVfbmFtZSkgJT4lIAogIGJpdHIoJ1RBSVInLCBjKCJHRU5FTkFNRSIsICJFTlRSRVpJRCIpLCAnb3JnLkF0LnRhaXIuZGInKSAlPiUgCiAgZGlzdGluY3QoVEFJUiwgLmtlZXBfYWxsID0gVCkKCmBgYArQoXJlYXRpbmcgYSByYW5rIHZlY3RvcgpgYGB7cn0KcmFua3NfZm9yX2dzZWEgPC0gcmVzICU+JSAKICBhcy5kYXRhLmZyYW1lKCkgJT4lICAgCiAgbmEub21pdCgpICU+JSAKICBhcnJhbmdlKGRlc2Moc3RhdCkpICU+JSAKICByb3duYW1lc190b19jb2x1bW4oImdlbmVfbmFtZSIpICU+JQogIG11dGF0ZShUQUlSID0gZ3N1YigiXFwuXFxkKyQiLCAiIiwgZ2VuZV9uYW1lKSkgJT4lIAogIGxlZnRfam9pbih0cmFuc2xhdGVkX25hbWVzKSAlPiUgCiAgbXV0YXRlKE5BTUUgPSBpZmVsc2UoaXMubmEoRU5UUkVaSUQpLCBUQUlSLCBFTlRSRVpJRCkpICU+JSAKICB0cmFuc211dGUoTkFNRSwgc3RhdCkgJT4lIAogIGRlZnJhbWUoKQpgYGAKYGBge3J9CmhlYWQocmFua3NfZm9yX2dzZWEsIDEwMCkKYGBgCkZHU0VBIGNhbGN1bGF0aW5nCmBgYHtyfQpmZ3NlYV9yZXN1bHRzIDwtIGZnc2VhOjpmZ3NlYU11bHRpbGV2ZWwocGF0aHdheSwgcmFua3NfZm9yX2dzZWEpCmhlYWQoZmdzZWFfcmVzdWx0c1tvcmRlcihwdmFsKSwgXSkKYGBgCioqR1NFQSBwbG90IGZvciBvbmUgcGF0aCoqCgpgYGB7cn0KZmdzZWE6OnBsb3RFbnJpY2htZW50KHBhdGh3YXlbWyJTZWVkIGRldmVsb3BtZW50JVdpa2lQYXRod2F5c18yMDI0MDQxMCVXUDIyNzklQXJhYmlkb3BzaXMgdGhhbGlhbmEiXV0sIHJhbmtzX2Zvcl9nc2VhKSArIGxhYnModGl0bGU9IlNlZWQgZGV2ZWxvcG1lbnQiKQpgYGAKRHJhd2luZyB0aGUgdG9wIDEwIG1vc3QgZW5yaWNoZWQgcGF0aHMgZnJvbSB0aGUgdG9wIGFuZCBib3R0b20gb2YgdGhlIHJhbmtlZCBsaXN0CmBgYHtyfQp0b3BQYXRod2F5c1VwIDwtIGZnc2VhX3Jlc3VsdHNbRVMgPiAwXVtoZWFkKG9yZGVyKHB2YWwpLCBuPTEwKSwgcGF0aHdheV0KdG9wUGF0aHdheXNEb3duIDwtIGZnc2VhX3Jlc3VsdHNbRVMgPCAwXVtoZWFkKG9yZGVyKHB2YWwpLCBuPTEwKSwgcGF0aHdheV0KdG9wUGF0aHdheXMgPC0gYyh0b3BQYXRod2F5c1VwLCByZXYodG9wUGF0aHdheXNEb3duKSkKZmdzZWE6OnBsb3RHc2VhVGFibGUocGF0aHdheVt0b3BQYXRod2F5c10sIHJhbmtzX2Zvcl9nc2VhLCBmZ3NlYV9yZXN1bHRzLCAKICAgICAgICAgICAgICAgICAgICAgZ3NlYVBhcmFtPTAuNSkKYGBgCkZHU0VBIGJ5IGNsdXN0ZXJQcm9maWxlcgpgYGB7cn0KR09fZ3NlYSA8LSBnc2VHTyhyYW5rc19mb3JfZ3NlYSwgb250ID0gIkFMTCIsICdvcmcuQXQudGFpci5kYicsIGVwcyA9IDApCmBgYAoqKlJpZGdlIHBsb3QqKgpgYGB7cn0KcGx0IDwtIHJpZGdlcGxvdChHT19nc2VhLCBzaG93Q2F0ZWdvcnkgPSAyMCkKcGx0ICsgdGhlbWUoCiAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpCikKYGBgClNvbWUgb2YgdGhlIHBhdGhzIGNhbiBiZSByZWxhdGVkIHRvIHBsYW50IHdvdW5kaW5nIGFuZCBob3cgcGxhbnRzIHJlc3BvbmQgdG8gaW5qdXJ5IG9yIHN0cmVzczoKCjEuICoqVHJhbnNwb3J0ZXIgQWN0aXZpdHkqKjogCiAgIC0gKipBY3RpdmUgdHJhbnNtZW1icmFuZSB0cmFuc3BvcnRlciBhY3Rpdml0eSoqIGFuZCByZWxhdGVkIHRlcm1zIGludm9sdmUgdGhlIG1vdmVtZW50IG9mIG1vbGVjdWxlcyBhY3Jvc3MgY2VsbCBtZW1icmFuZXMuIFdoZW4gYSBwbGFudCBpcyB3b3VuZGVkLCBpdCBtYXkgbmVlZCB0byB0cmFuc3BvcnQgZGVmZW5zaXZlIGNvbXBvdW5kcywgc2lnbmFsaW5nIG1vbGVjdWxlcywgb3IgbnV0cmllbnRzIHRvIGFuZCBmcm9tIHRoZSBzaXRlIG9mIGluanVyeS4KCjIuICoqRGVmZW5zZSBSZXNwb25zZSB0byBPdGhlciBPcmdhbmlzbSoqOgogICAtIFRoaXMgdGVybSBkaXJlY3RseSByZWxhdGVzIHRvIGhvdyBwbGFudHMgZGVmZW5kIHRoZW1zZWx2ZXMgYWdhaW5zdCBoZXJiaXZvcmVzLCBwYXRob2dlbnMsIG9yIG90aGVyIHRocmVhdHMgdGhhdCBjb3VsZCBjYXVzZSB3b3VuZGluZy4gUGxhbnRzIG9mdGVuIGluaXRpYXRlIGRlZmVuc2UgbWVjaGFuaXNtcywgaW5jbHVkaW5nIHRoZSBwcm9kdWN0aW9uIG9mIHNlY29uZGFyeSBtZXRhYm9saXRlcyBhbmQgc2lnbmFsaW5nIGNvbXBvdW5kcywgaW4gcmVzcG9uc2UgdG8gd291bmRpbmcuCgozLiAqKlByb3RlaW4gTW9kaWZpY2F0aW9uIFByb2Nlc3MqKjoKICAgLSAqKlByb3RlaW4gbW9kaWZpY2F0aW9uIHByb2Nlc3NlcyoqIGFyZSBjcnVjaWFsIGluIHRoZSBwbGFudCdzIHJlc3BvbnNlIHRvIHdvdW5kaW5nLiBGb3IgZXhhbXBsZSwgcG9zdC10cmFuc2xhdGlvbmFsIG1vZGlmaWNhdGlvbnMgb2YgcHJvdGVpbnMgY2FuIGJlIGludm9sdmVkIGluIHNpZ25hbGluZyBwYXRod2F5cyB0aGF0IGFjdGl2YXRlIGRlZmVuc2UgbWVjaGFuaXNtcy4KCjQuICoqQmluZGluZyBBY3Rpdml0aWVzKio6CiAgIC0gKipBbmlvbiBiaW5kaW5nKiosICoqcHVyaW5lIG51Y2xlb3RpZGUgYmluZGluZyoqLCBhbmQgc2ltaWxhciB0ZXJtcyBtYXkgYmUgaW52b2x2ZWQgaW4gdGhlIHJlY29nbml0aW9uIGFuZCByZXNwb25zZSB0byBzdHJlc3Mgc2lnbmFscy4gVGhlc2UgYmluZGluZyBhY3Rpdml0aWVzIGNhbiBhZmZlY3QgaG93IHBsYW50cyBwZXJjZWl2ZSBhbmQgcmVhY3QgdG8gd291bmRpbmcuCgo1LiAqKlJlc3BvbnNlIHRvIElub3JnYW5pYyBTdWJzdGFuY2UqKjoKICAgLSBUaGlzIGNvdWxkIHJlbGF0ZSB0byBob3cgcGxhbnRzIHJlc3BvbmQgdG8gY2hhbmdlcyBpbiBpb24gY29uY2VudHJhdGlvbnMgb3Igb3RoZXIgaW5vcmdhbmljIHN1YnN0YW5jZXMgcmVsZWFzZWQgb3IgbW9iaWxpemVkIGR1cmluZyB3b3VuZGluZy4KCjYuICoqVmFjdW9sZSoqIGFuZCAqKkNobG9yb3BsYXN0IEVudmVsb3BlKio6CiAgIC0gQ2VsbHVsYXIgY29tcGFydG1lbnRzIGxpa2UgdGhlIHZhY3VvbGUgYW5kIGNobG9yb3BsYXN0IGVudmVsb3BlIG1heSBwbGF5IHJvbGVzIGluIHRoZSBzdG9yYWdlIGFuZCByZWxlYXNlIG9mIGNvbXBvdW5kcyByZWxhdGVkIHRvIHRoZSB3b3VuZCByZXNwb25zZS4gRm9yIGluc3RhbmNlLCB2YWN1b2xlcyBjYW4gc3RvcmUgZGVmZW5zaXZlIGNvbXBvdW5kcyBvciBzaWduYWxpbmcgbW9sZWN1bGVzLgoKNy4gKipMaXBpZCBNZXRhYm9saWMgUHJvY2VzcyoqOgogICAtIExpcGlkIG1ldGFib2xpc20gaXMgb2Z0ZW4gaW52b2x2ZWQgaW4gdGhlIHN5bnRoZXNpcyBvZiBzaWduYWxpbmcgbW9sZWN1bGVzIGxpa2UgamFzbW9uaWMgYWNpZCwgd2hpY2ggaXMgY3J1Y2lhbCBmb3IgdGhlIHdvdW5kIHJlc3BvbnNlIGluIHBsYW50cy4KCjguICoqRGVmZW5zZSBhbmQgU3RyZXNzIFJlc3BvbnNlcyoqOgogICAtIFRlcm1zIHJlbGF0ZWQgdG8gKipkZWZlbnNlIHJlc3BvbnNlcyoqIGFuZCAqKnN0cmVzcyByZXNwb25zZXMqKiBhcmUgcGFydGljdWxhcmx5IHJlbGV2YW50IHRvIHdvdW5kaW5nLiBQbGFudHMgYWN0aXZhdGUgdmFyaW91cyBzaWduYWxpbmcgcGF0aHdheXMgYW5kIHByb2R1Y2UgcHJvdGVjdGl2ZSBjb21wb3VuZHMgaW4gcmVzcG9uc2UgdG8gcGh5c2ljYWwgZGFtYWdlLgpgYGB7cn0KZ3NlYXBsb3QoR09fZ3NlYSwgMSwgdGl0bGUgPSBHT19nc2VhQHJlc3VsdCREZXNjcmlwdGlvbltbMV1dKQpgYGAKCg==